﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace Framework.Bus
{
    public class MessageDispatcher : IMessageDispatcher
    {
        private readonly Dictionary<Type, List<Action<dynamic>>> dispatcherActions;
        private readonly Hashtable discardKeyTypes;
        public MessageDispatcher()
        {
            dispatcherActions = new Dictionary<Type, List<Action<dynamic>>>();
            discardKeyTypes = new Hashtable();
        }

        public void ClearRegistration()
        {
            dispatcherActions.Clear();
        }

        public void DispatchMessage(object message)
        {
            var keyType = message.GetType();
            if (dispatcherActions.ContainsKey(keyType))
            {
                var messageDispatcherActions = dispatcherActions[keyType];
                if (messageDispatcherActions != null && messageDispatcherActions.Count > 0)
                {
                    foreach (var action in messageDispatcherActions)
                    {
                        action(message);
                    }
                }
            }
            else if (!discardKeyTypes.Contains(keyType))
            {
                bool isDiscardKeyTypes = true;
                foreach(var dispatcherAction in dispatcherActions)
                {
                    if (keyType.IsSubclassOf(dispatcherAction.Key))
                    {
                        var messageDispatcherActions = dispatcherActions[dispatcherAction.Key];
                        if (messageDispatcherActions != null && messageDispatcherActions.Count > 0)
                        {
                            foreach (var action in messageDispatcherActions)
                            {
                                action(message);
                            }
                            isDiscardKeyTypes = false;
                            dispatcherActions.Add(keyType, messageDispatcherActions);
                            break;
                        }
                    }
                }
                if (isDiscardKeyTypes)
                {
                    discardKeyTypes.Add(keyType, keyType);
                }
            }
        }

        public void Register<T>(IHandler<T> handler)
        {
            Type keyType = typeof(T);
            Action<dynamic> action = p => handler.Handle(p);

            if (dispatcherActions.ContainsKey(keyType))
            {
                List<Action<dynamic>> registeredDispatcherActions = dispatcherActions[keyType];
                if (registeredDispatcherActions != null)
                {
                    if (!registeredDispatcherActions.Contains(action))
                        registeredDispatcherActions.Add(action);
                }
                else
                {
                    registeredDispatcherActions = new List<Action<dynamic>>();
                    dispatcherActions[keyType] = registeredDispatcherActions;
                    registeredDispatcherActions.Add(action);
                }
            }
            else
            {
                List<Action<dynamic>> registeredDispatcherActions = new List<Action<dynamic>>();
                registeredDispatcherActions.Add(action);
                dispatcherActions.Add(keyType, registeredDispatcherActions);
            }
        }
    }
}
